package com.shadow.demo.dictionary.common;


import com.sun.javafx.PlatformUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.io.File;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Pattern;

/**
 * 文件处理类
 *
 * @author penggch
 */
@Slf4j
public class PathUtil {

    /**
     * 根路径
     */
    public static final String root = "/";
    /**
     * 路径分隔符
     */
    public static final String separator = "/";
    /**
     * 当前目录
     */
    public static final String focusDir = ".";
    /**
     * 上层目录
     */
    public static final String lastDir = "..";

    private static List<String> EnvPaths = new ArrayList<String>();

    /**
     * 系统临时目录
     */
    private static File SysTmpDir = null;
    /**
     * 应用临时目录
     */
    private static File AppTmpDir = null;

    private static Object uniqueLock = new Object();
    private static String uniqueSeconds = null;
    private static int uniqueIndex = 36;
    private static String processId = null;

    private static final String REPLACE_UNIQUE_REGEX1 = "_[a-z0-9A-Z]{1,}_[a-z0-9A-Z]{1,}$";
    private static final String REPLACE_UNIQUE_REGEX2 = "_[a-z0-9A-Z]{1,}_[a-z0-9A-Z]{1,}\\.";

    /**
     * 获取唯一文件名
     *
     * @param filename 文件名
     * @return
     */
    public static String uniqueFile(String filename) {
        if (filename == null || filename.length() == 0) {
            filename = unique();
        } else {
            filename = filename.replaceAll(REPLACE_UNIQUE_REGEX1, StringUtils.EMPTY);
            filename = filename.replaceAll(REPLACE_UNIQUE_REGEX2, ".");
            String prefix = StringUtils.EMPTY;
            String suffix = StringUtils.EMPTY;
            int idx = filename.indexOf(".");
            if (idx == 0) {
                prefix = "f";
                suffix = filename;
            } else if (idx > 0) {
                prefix = filename.substring(0, idx);
                suffix = filename.substring(idx);
            } else {
                prefix = filename;
            }
            filename = unique(prefix, suffix);
        }
        return filename;
    }

    /**
     * 获取唯一值(进程唯一)
     *
     * @return
     */
    public static String unique() {
        return unique(null, null);
    }

    /**
     * 获取唯一值(进程唯一)
     *
     * @param suffix
     * @return
     */
    public static String unique(String suffix) {
        return unique(null, null);
    }

    /**
     * 获取唯一值(进程唯一)
     *
     * @param prefix 前缀
     * @param suffix 后缀
     * @return 唯一名称
     */
    public static String unique(String prefix, String suffix) {
        synchronized (uniqueLock) {
            if (prefix == null) {
                prefix = "u";
            }
            if (suffix == null) {
                suffix = "";
            }
            Calendar calendar = Calendar.getInstance();
            // 取得秒值字符串
            String timeStr = toString36((int) calendar.getTimeInMillis() / 1000);
            if (timeStr.equals(uniqueSeconds)) {
                // 同一秒内，递增
                uniqueIndex++;
            } else {
                // 不同秒，超过100
                uniqueIndex = uniqueIndex > 1137 ? 37 : uniqueIndex + 1;
            }
            return prefix + "_" + getProcessId() + "_" + toString36(uniqueIndex) + timeStr + suffix;
        }
    }

    private static String toString36(int i) {
        return Integer.toString(i, 36).replace("-", "");
    }

    /**
     * 获取进程Id
     *
     * @return
     */
    private static String getProcessId() {
        if (processId == null || processId.length() == 0) {
            processId = ManagementFactory.getRuntimeMXBean().getName().split("@")[0];
            processId = toString36(Integer.parseInt(processId));
        }
        return processId;
    }

    /**
     * 获取系统临时目录
     *
     * @return
     */
    public static File getSysTmpDir() {
        if (SysTmpDir == null) {
            SysTmpDir = new File(System.getProperty("java.io.tmpdir"));
        }
        if (!SysTmpDir.exists() && !SysTmpDir.mkdirs()) {
            throw new RuntimeException("创建系统临时目录失败！[path:" + SysTmpDir.getAbsolutePath() + "]");
        }
        return SysTmpDir;
    }

    /**
     * 获取临时目录
     *
     * @return 临时目录
     */
    public static File getTmpDir() {
        if (AppTmpDir == null) {
            AppTmpDir = new File(getSysTmpDir(), "DistTemp");
        }
        if (!AppTmpDir.exists() && !AppTmpDir.mkdirs()) {
            throw new RuntimeException("创建应用临时目录失败！[path:" + AppTmpDir.getAbsolutePath() + "]");
        }
        return AppTmpDir;
    }

    /**
     * 获取临时目录
     *
     * @param subPath 子路径
     * @return 临时目录
     */
    public static File getTmpDir(String subPath) {
        if (subPath == null || subPath.length() == 0) {
            return getTmpDir();
        }
        File dir = new File(getTmpDir(), subPath);
        if (!dir.exists() && !dir.mkdirs()) {
            throw new RuntimeException("创建临时目录失败！[path:" + dir.getAbsolutePath() + "]");
        }
        return dir;
    }

    /**
     * 获取文件或路径的名称
     *
     * @param path 文件全路径或目录全路径
     * @return 文件或路径的名称
     */
    public static String getName(String path) {
        if (StringUtils.isEmpty(path)) {
            return StringUtils.EMPTY;
        } else if (path.endsWith(separator)) {
            path = path.substring(0, path.length() - 1);
        }
        return path.substring(path.lastIndexOf(separator) + 1);
    }

    /**
     * 获取文件名，不带扩展名
     *
     * @param filename 文件名
     * @return
     */
    public static String getFileNameWithoutExt(String filename) {
        filename = getName(filename);
        if (filename != null && filename.length() > 0 && filename.lastIndexOf(".") > -1) {
            return filename.substring(0, filename.lastIndexOf("."));
        } else {
            return filename;
        }
    }

    /**
     * 获取文件扩展名（不带点）
     *
     * @param filename 文件名
     * @return
     */
    public static String getFileExtWithoutDot(String filename) {
        filename = getName(filename);
        if (filename != null && filename.length() > 0 && filename.lastIndexOf(".") > -1) {
            return filename.substring(filename.lastIndexOf(".") + 1);
        } else {
            return StringUtils.EMPTY;
        }
    }

    /**
     * 获取文件扩展名（带点）
     *
     * @param filename 文件名
     * @return
     */
    public static String getFileExt(String filename) {
        filename = getName(filename);
        if (filename != null && filename.length() > 0 && filename.lastIndexOf(".") > -1) {
            return filename.substring(filename.lastIndexOf("."));
        } else {
            return StringUtils.EMPTY;
        }
    }

    /**
     * 获取文件名，不带扩展名
     *
     * @param filename 文件名
     * @return
     */
    public static String getSimpleName(String filename) {
        filename = getName(filename);
        if (filename != null && filename.length() > 0) {
            filename = filename.replaceAll(REPLACE_UNIQUE_REGEX1, StringUtils.EMPTY);
            filename = filename.replaceAll(REPLACE_UNIQUE_REGEX2, ".");
            if (filename.lastIndexOf(".") > -1) {
                filename = filename.substring(0, filename.lastIndexOf("."));
            }
        }
        return filename;
    }

    /**
     * 获取文件扩展名（不带点）
     *
     * @param filename 文件名
     * @return
     */
    public static String getSimpleExt(String filename) {
        filename = getName(filename);
        if (filename != null && filename.length() > 0 && filename.lastIndexOf(".") > -1) {
            return filename.substring(filename.lastIndexOf(".") + 1);
        } else {
            return StringUtils.EMPTY;
        }
    }

    /**
     * 创建临时文件
     *
     * @param filename
     * @return
     */
    public static File createTmpFile(String filename) {
        filename = uniqueFile(filename);
        File dir = getTmpDir();
        File file = new File(dir, filename);
        try {
            if (!file.getParentFile().exists()) {
                file.getParentFile().mkdirs();
            }
            if (file.createNewFile()) {
                return file;
            } else {
                throw new RuntimeException();
            }
        } catch (IOException e) {
            throw new RuntimeException("文件创建失败！[filename:" + filename + "]", e);
        }
    }

    /**
     * 创建临时文件
     *
     * @param prefix 前缀
     * @param suffix 后缀
     * @return
     */
    public static File createTmpFile(String prefix, String suffix) {
        File dir = getTmpDir();
        return createTmpFile(prefix, suffix, dir);
    }

    /**
     * 创建临时文件
     *
     * @param prefix 前缀
     * @param suffix 后缀
     * @param dir    指定目录
     * @return
     */
    public static File createTmpFile(String prefix, String suffix, File dir) {
        File file;
        try {
            if (dir == null) {
                dir = getTmpDir();
            }
            String name = unique(prefix, suffix);
            file = new File(dir, name);
            if (!file.createNewFile()) {
                throw new RuntimeException();
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return file;
    }

    /**
     * 创建临时目录
     *
     * @param dirname 目录名称
     * @return
     */
    public static File createTmpDir(String dirname) {
        dirname = unique(dirname, null);
        File dir = getTmpDir();
        dir = new File(dir, dirname);
        if (dir.mkdirs()) {
            return dir;
        } else {
            throw new RuntimeException("目录创建失败！");
        }
    }

    /**
     * 创建新的临时目录（全新的目录）
     *
     * @param prefix 目录前缀
     * @param suffix 目录后缀
     * @return
     */
    public static File createTmpDir(String prefix, String suffix) {
        if (prefix == null || prefix.length() == 0) {
            prefix = "d";
        }
        if ((suffix == null || suffix.length() == 0) && prefix.length() > 0 && prefix.lastIndexOf(".") > -1) {
            suffix = prefix.substring(prefix.lastIndexOf("."));
            prefix = prefix.substring(0, prefix.lastIndexOf("."));
        }
        String name = unique(prefix, suffix);
        File dir = getTmpDir();
        dir = new File(dir, name);
        if (dir.mkdirs()) {
            return dir;
        } else {
            throw new RuntimeException("目录创建失败！");
        }
    }

    /**
     * 创建日期目录
     *
     * @param parentDir 上级目录
     * @return
     */
    public static File createDateDir(File parentDir) {
        String path = DateUtil.formatDate(new Date()).replaceAll("-", "/");
        File file = new File(parentDir, path);
        if (!file.exists()) {
            file.mkdirs();
        }
        return file;
    }

    /**
     * 获取class目录
     *
     * @return ./classes/或./bin/
     */
    public static String getClassPath() {
        String rootPath = null;
//        try {
//            rootPath = ResourceUtils.getURL("classpath:").getPath();
//            rootPath = CodeUtil.urlDecode(rootPath);
//        } catch (Exception e) {
//            log.error("", e);
//        }
//        if (rootPath == null || rootPath.length() == 0) {
//            rootPath = new File(PathUtil.class.getClassLoader().getResource("").getPath()).getAbsolutePath();
//        }
        return rootPath;
    }

    /**
     * 获取绝对路径
     *
     * @param path 文件路径
     * @return 绝对路径，如果是目录，路径结尾不带斜线或者反斜线
     */
    public static String getAbsolutePath(String path) {
        String result = path;
        if (path == null || path.length() == 0) {
            result = StringUtils.EMPTY;
        } else if (path.toLowerCase().startsWith("classpath:")) {
            URL url = PathUtil.class.getClassLoader().getResource(path.substring(10).trim());
            if (url != null) {
                result = url.getPath();
            }
        } else if (path.toLowerCase().startsWith("absolutepath:")) {
            result = path.substring(13).trim();
        } else if (path.toLowerCase().startsWith("envpath:")) {
            result = System.getenv(path.substring(8).trim());
        } else if (path.toLowerCase().startsWith("webinfpath:")) {
            URL url = PathUtil.class.getClassLoader().getResource("/");
            if (url != null) {
                File dir = new File(url.getPath());
                if (dir.getName().equalsIgnoreCase("classes")
                        && dir.getParentFile().getName().equalsIgnoreCase("WEB-INF")) {
                    dir = dir.getParentFile();
                    return new File(dir, path.substring(11)).getAbsolutePath();
                }
            }
        } else if (path.toLowerCase().startsWith("contextpath:")) {
            URL url = PathUtil.class.getClassLoader().getResource("/");
            File dir = null;
            if (url == null) {
                url = PathUtil.class.getClassLoader().getResource("");
                dir = new File(url.getPath());
            } else {
                dir = new File(url.getPath());
                if (dir.getName().equalsIgnoreCase("classes")
                        && dir.getParentFile().getName().equalsIgnoreCase("WEB-INF")) {
                    dir = dir.getParentFile().getParentFile();
                }
            }
            return new File(dir, path.substring(12)).getAbsolutePath();
        }
        if (result != null && (result.endsWith("/") || result.endsWith("\\"))) {
            result = result.substring(0, result.length() - 1);
        }
        return result;
    }

    /**
     * 路径格式化，null：0长字符串；\转为separator；多个separator转为一个；非根路径去掉结尾的separator
     *
     * @param path 原始路径
     * @return 格式化之后的路径
     */
    public static String formatPath(String path) {
        if (path == null) {
            path = StringUtils.EMPTY;
        }
        path = path.replaceAll("(\\/|\\\\){1,}", separator);
        return path;
    }

    /**
     * 获取文件或路径的上级目录
     *
     * @param path 文件全路径或目录全路径
     * @return 文件或路径的上级目录
     */
    public static String getParentPath(String path) {
        if (StringUtils.isEmpty(path)) {
            return StringUtils.EMPTY;
        } else if (separator.equals(path)) {
            return separator;
        } else if (path.endsWith(separator)) {
            path = path.substring(0, path.length() - 1);
        }
        int idx = path.lastIndexOf(separator);
        if (idx == -1) {
            path = StringUtils.EMPTY;
        } else if (idx == 0) {
            path = separator;
        } else {
            path = path.substring(0, path.lastIndexOf(separator) + 1);
        }
        return path;
    }

    public static List<String> listEnvPath() {
        if (EnvPaths.size() == 0) {
            String path1 = System.getProperty("java.library.path");
            String path2 = System.getenv("PATH");
            if (path1 != null) {
                String[] paths = null;
                if (PlatformUtil.isWindows()) {
                    paths = path1.split(";");
                } else {
                    paths = path1.split(":");
                }
                for (String path : paths) {
                    if (path.trim().length() > 0 && !EnvPaths.contains(path.trim())) {
                        EnvPaths.add(path.trim());
                    }
                }
            }
            if (path2 != null) {
                String[] paths = null;
                if (PlatformUtil.isWindows()) {
                    paths = path2.split(";");
                } else {
                    paths = path2.split(":");
                }
                for (String path : paths) {
                    if (path.trim().length() > 0 && !EnvPaths.contains(path.trim())) {
                        EnvPaths.add(path.trim());
                    }
                }
            }
        }
        return new ArrayList<String>(EnvPaths);
    }

    public static File searchOneInExePath(Pattern searchPattern) {
        File file = null;
        if (PlatformUtil.isWindows()) {
            file = searchOne("C:\\Windows\\System32", searchPattern);
        } else {
            file = searchOne("/usr/bin", searchPattern);
            if (file == null) {
                file = searchOne("/usr/local/bin", searchPattern);
            }
        }
        return file;
    }

    public static File searchOneInEnvPath(Pattern searchPattern) {
        List<String> paths = listEnvPath();
        File file = null;
        for (String path : paths) {
            File dir = new File(path);
            if (!dir.exists()) {
                continue;
            }
            file = searchOne(dir, searchPattern, false);
            if (file != null) {
                break;
            }
        }
        return file;
    }

    /**
     * 通过注册表查找，在注册表中找到目录，然后在该目录中查找
     *
     * @param searchPattern
     * @param regeditKey
     * @param regeditValueName
     * @return
     */
    public static File searchOnInRegedit(Pattern searchPattern, String regeditKey, String regeditValueName) {
        File file = null;
        if (PlatformUtil.isWindows()) {
            String path = RegeditUtil.tryReadString(RegeditUtil.HKEY_CURRENT_USER, regeditKey, regeditValueName);
            file = searchOne(path, searchPattern);
            if (file == null) {
                path = RegeditUtil.tryReadString(RegeditUtil.HKEY_CURRENT_USER, regeditKey, regeditValueName);
                file = searchOne(path, searchPattern);
            }
        }
        return file;
    }

    public static File searchOneInHome(Pattern searchPattern, String homeKey) {
        String path = System.getenv(homeKey);
        File file = searchOne(path, searchPattern);
        return file;
    }

    public static File searchOne(String dirPath, Pattern searchPattern) {
        if (StringUtils.isEmpty(dirPath)) {
            return null;
        }
        File dir = new File(dirPath);
        if (!dir.exists()) {
            return null;
        }

        return searchOne(dir, searchPattern);
    }

    public static File searchOne(File dir, Pattern searchPattern) {
        return searchOne(dir, searchPattern, true);
    }

    public static File searchOne(File dir, Pattern searchPattern, boolean subtree) {
        File[] files = dir.listFiles();
        File file = null;
        if (files != null && files.length > 0) {
            for (File f : files) {
                if (f.isFile() && searchPattern.matcher(f.getName()).find()) {
                    file = f;
                    break;
                }
            }
            if (subtree) {

                for (File f : files) {
                    if (f.isDirectory()) {
                        file = searchOne(f, searchPattern);
                    }
                    if (file != null) {
                        break;
                    }
                }
            }

        }
        return file;
    }

    /**
     * 获取文件名
     *
     * @param fullFileName
     * @return
     */
    public static String getFileName(String fullFileName) {
        int slantIndex = fullFileName.lastIndexOf("/");
        int backslashIndex = fullFileName.lastIndexOf("\\");

        int index = slantIndex > backslashIndex ? slantIndex : backslashIndex;
        return fullFileName.substring(index + 1);
    }

    /**
     * 获取不带扩展名的文件名
     *
     * @param fullFileName
     * @return
     */
    public static String getFileNameWithoutExtension(String fullFileName) {
        String fileName = getFileName(fullFileName);
        int index = fileName.lastIndexOf(".");
        return index > 0 ? fileName.substring(0, index) : fileName;
    }

    /**
     * 合并路径
     *
     * @param routerPath
     * @param paths
     * @return
     */
    public static String combine(String routerPath, String... paths) {
        Path path1 = Paths.get(routerPath);
        for (String path : paths) {
            path1 = path1.resolve(path);
        }
        return path1.toString();
    }
}
